﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;

namespace LCA.Common.Extensions
{
    public static class StringExtensions
    {
        private static NumberFormatInfo FORMAT_PROVIDER_EN = CultureInfo.GetCultureInfo("en-US").NumberFormat;

        public static string ToInitCap(this string s)
        {
            if (s == null || s.Length == 0)
            {
                return "";
            }
            return Char.ToUpper(s[0]) + s.Substring(1).ToLower();
        }

        public static string FirstUpper(this string s)
        {
            if (s == null || s.Length == 0)
            {
                return "";
            }
            return Char.ToUpper(s[0]) + s.Substring(1);
        }

        public static string FirstLower(this string s)
        {
            if (s == null || s.Length == 0)
            {
                return "";
            }
            return Char.ToLower(s[0]) + s.Substring(1);
        }

        public static string Truncate(this string s, int maxlen)
        {
            return (s.Length <= maxlen) ? s : s.Substring(0, maxlen);
        }

        public static string TruncateAtWord(this string s, int maxlen, string trailingStringIfTextCut = null)
        {
            if (s.Length <= maxlen)
                return s;

            if (trailingStringIfTextCut == null)
                trailingStringIfTextCut = "";

            maxlen = Math.Max(maxlen - trailingStringIfTextCut.Length, 0);

            int index = s.LastIndexOf(" ", maxlen);
            return s.Substring(0, index > 0 ? index : maxlen) + trailingStringIfTextCut;
        }

        public static DateTime? ToDateTime(this string s)
        {
            return ToDateTime(s, (DateTime?)null);
        }

        public static DateTime? ToDateTime(this string s, DateTime? _default)
        {
            DateTime result;
            if (DateTime.TryParse(s, FORMAT_PROVIDER_EN, DateTimeStyles.None, out result))
                return result;
            else
                return _default;
        }

        public static DateTime? ToDateTime(this string s, string format)
        {
            return ToDateTime(s, format, (DateTime?)null);
        }

        public static DateTime? ToDateTime(this string s, string format, DateTime? _default)
        {
            DateTime result;
            if (DateTime.TryParseExact(s, format, FORMAT_PROVIDER_EN, DateTimeStyles.None, out result))
                return result;
            else
                return _default;
        }

        public static int? ToInt(this string s)
        {
            return ToInt(s, null);
        }

        public static int? ToInt(this string s, int? _default)
        {
            int result;
            if (Int32.TryParse(s, NumberStyles.Integer, FORMAT_PROVIDER_EN, out result))
                return result;
            else
                return _default;
        }

        public static double? ToDouble(this string s)
        {
            return ToDouble(s, null);
        }

        public static double? ToDouble(this string s, double? _default)
        {
            double result;
            if (Double.TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, FORMAT_PROVIDER_EN, out result))
                return result;
            else
                return _default;
        }

        public static bool? ToBoolean(this string s)
        {
            return ToBoolean(s, null);
        }

        public static bool? ToBoolean(this string s, bool? _default)
        {
            bool result;
            if (Boolean.TryParse(s, out result))
                return result;
            else if (String.Equals(s, "yes", StringComparison.InvariantCultureIgnoreCase))
                return true;
            else if (String.Equals(s, "no", StringComparison.InvariantCultureIgnoreCase))
                return false;
            else if (s == "1")
                return true;
            else if (s == "0")
                return false;
            else
                return _default;
        }

        public static T ToEnum<T>(this string s, T _default)
        {
            try
            {
                return (T)Enum.Parse(typeof(T), s.Replace(" ", ""), true);
            }
            catch
            {
                return _default;
            }
        }

        public static Guid? ToGuid(this string s)
        {
            return ToGuid(s, null);
        }

        public static Guid? ToGuid(this string s, Guid? _default)
        {
            Guid result;
            if (Guid.TryParse(s, out result))
                return result;
            else
                return _default;
        }

        public static decimal? ToDecimal(this string s)
        {
            return ToDecimal(s, null);
        }

        public static decimal? ToDecimal(this string s, decimal? _default)
        {
            decimal result;
            if (Decimal.TryParse(s, NumberStyles.Float | NumberStyles.AllowThousands, FORMAT_PROVIDER_EN, out result))
                return result;
            else
                return _default;
        }

        public static string ToFriendlyUrl(this string s)
        {
            return Regex.Replace(s, @"[^\w\d]+", "-").Trim('-');
            //return Regex.Replace(s, @"[^\w\d ]+", string.Empty).Replace(" ", "-");
        }

        //public static string HtmlEncode(this string s)
        //{
        //    return System.Web.HttpUtility.HtmlEncode(s);
        //}

        private static readonly IList<string> Unpluralizables = new List<string> { "equipment", "information", "rice", "money", "species", "series", "fish", "sheep", "deer" };
        private static readonly IDictionary<string, string> Pluralizations = new Dictionary<string, string>
    {
        // Start with the rarest cases, and move to the most common
        { "person", "people" },
        { "ox", "oxen" },
        { "child", "children" },
        { "foot", "feet" },
        { "tooth", "teeth" },
        { "goose", "geese" },
        // And now the more standard rules.
        { "(.*)fe?", "$1ves" },         // ie, wolf, wife
        { "(.*)man$", "$1men" },
        { "(.+[aeiou]y)$", "$1s" },
        { "(.+[^aeiou])y$", "$1ies" },
        { "(.+z)$", "$1zes" },
        { "([m|l])ouse$", "$1ice" },
        { "(.+)(e|i)x$", @"$1ices"},    // ie, Matrix, Index
        { "(octop|vir)us$", "$1i"},
        { "(.+(s|x|sh|ch))$", @"$1es"},
        { "(.+)", @"$1s" }
    };

        public static string Pluralize(this string singular)
        {
            return Pluralize(singular, true);
        }

        public static string Pluralize(this string singular, int count)
        {
            return Pluralize(singular, count != 1);
        }

        public static string Pluralize(this string singular, bool isPlural)
        {
            if (!isPlural)
                return singular;

            if (Unpluralizables.Contains(singular))
                return singular;

            var plural = "";

            foreach (var pluralization in Pluralizations)
            {
                if (Regex.IsMatch(singular, pluralization.Key))
                {
                    plural = Regex.Replace(singular, pluralization.Key, pluralization.Value);
                    break;
                }
            }

            return plural;
        }
    }
}
